﻿/**
 * Mootools框架扩展库
 * 使用方法请参考文档
 * 
 * 作者：PPLive.com
 * 日期：2008-12-15
 * 修改：2008-12-22
 * 版本：0.0.2.0
 * 
 */

/*
* MooTools的Window类的扩展
* 全局方法
* 
*/
Window.implement({
    $params: function(delimiter) {
        ///<summary>
        /// 获取页面URL的参数，返回包含参数的hash对象
        ///</summary>
        ///<param name="delimiter" type="String">参数和URL的分隔符，比如?或者#，默认为#</param>
        ///<returns type="Hash" />
        delimiter = (delimiter || '#').escapeRegExp();
        var params = new Hash();
        try {
            var requestStr = (location.toString().match(new RegExp(delimiter + '(.+)$')) || [0, 0])[1];
            if (requestStr) {
                params = requestStr.toHash(true);
            }
        }
        catch (e) {
        }
        return params;
    },

    $dump: function(obj, options) {
        ///<summary>
        /// 打印一个变量或者对象的内容，返回描述变量内容的字符串
        ///</summary>
        ///<param name="obj" type="Object">要打印的变量</param>
        ///<param name="options" type="Object">
        /// 选项：
        ///   delimiter: 变量描述之间的分隔符，默认为“, ”；
        ///   showFunction: 是否打印函数内容，默认为false；
        ///   showClass: 是否打印类的构造函数，默认为false；
        ///   showArrayValue: 是否打印数组内容，默认为true；
        ///   sort: 排序方式，默认不排序，可以为asc（顺序）, desc（逆序）
        ///</param>
        ///<returns type="Hash" />
        options = options || {};
        var dlm = options.delimiter || ', ';
        var rf = options.showFunction ? true : false;
        var rc = options.showClass ? true : false;
        var rav = options.showArrayValue === false ? false : true;   // 只有为false时是false，没指定为true
        var st = options.sort ? options.sort : null;
        var s = [];
        switch ($type(obj)) {
            case 'element':
            case 'hash':
            case 'native':
            case 'object':
            case 'window':
                var v, ty;
                for (var p in obj) {
                    try {
                        v = obj[p];
                        ty = $type(v);

                        if ('function' == ty && !rf) {
                            s.push(['[', p, '](', ty, ') => [function Function]'].join(''));
                        }
                        else if (('class' == ty || 'native' == ty) && !rc) {
                            s.push(['[', p, '](', ty, ') => [class Class]'].join(''));
                        }
                        else if ('string' == ty) {
                            s.push(['[', p, '](', ty, ' ', v.length, ') => ', v].join(''));
                        }
                        else if ('array' == ty) {
                            if (rav && rf) {
                                s.push(['[', p, '](', ty, ' ', v.length, ') => ', v].join(''));
                            }
                            else if (rav && !rf) {
                                var tv, tty, ta = [], len = v.length;
                                for (var i = 0; i < len; i++) {
                                    if ('function' == $type(v[i])) {
                                        ta.push('[function Function]');
                                    }
                                    else {
                                        ta.push(v[i]);
                                    }
                                }
                                s.push(['[', p, '](', ty, ' ', v.length, ') => ', ta].join(''));
                            }
                            else {
                                s.push(['[', p, '](', ty, ' ', v.length, ') => [array Array]'].join(''));
                            }
                        }
                        else {
                            s.push(['[', p, '](', ty, ') => ', v].join(''));
                        }
                    }
                    catch (e) {
                        ty = 'unknow';
                        v = '[Permission Denied]';
                        s.push(['[', p, '](', ty, ') => ', v].join(''));
                    }
                }
                break;
            case 'array':
                var l = obj.length;
                var v, t;
                for (var i = 0; i < l; i++) {
                    v = obj[i];
                    t = $type(v);
                    if ('function' == t && !rf) {
                        s.push(['[', i, '](', ty, ') => [function Function]'].join(''));
                    }
                    else {
                        s.push(['[', i, '](', ty, ') => ', v].join(''));
                    }
                }
                break;
            case 'string':
                s.push([$type(obj), ' ', obj.length, ' => ', obj].join(''));
                break;
            default:
                s.push([$type(obj), ' => ', obj].join(''));
                break;
        }

        if (st) {
            return s.sortBy({ type: st }).join(dlm);
        }

        return s.join(dlm);
    }
});

/*
* MooTools的String类的扩展
* 
*/
String.implement({
    startsWith: function(s) {
        ///<summary>
        /// 检查一个字符串是不是以某个字符串开头
        ///</summary>
        ///<param name="s" type="String">开始字符串</param>
        ///<returns type="BOOLEAN" />
        return (this.indexOf(s) == 0);
    },

    truncate: function(len, ae) {
        ///<summary>
        /// 按指定长度截取字符串
        /// 可以选择在截取字符串的后面添加或者不添加省略号（三个点）
        ///</summary>
        ///<param name="len" type="Number">要截取的字符串长度</param>
        ///<param name="ae" type="Boolean">true添加省略号，false不添加</param>
        ///<returns type="STRING" />
        if (this.length <= len) {
            return this;
        }
        else {
            var tl = 0, ts = [];
            var tt = this.length;
            for (var i = 0; i < tt; i++) {
                if (this.charCodeAt(i) > 255) {
                    tl += 2;
                }
                else {
                    tl++;
                }
                if (tl > len) {
                    break;
                }
                ts.push(this.charAt(i));
            }
            return ae ? ts.join('') + '...' : ts.join('');
        }
    },

    escapseHTML: function() {
        ///<summary>
        /// 对字符中的HTML代码进行转义
        ///</summary>
        ///<returns type="STRING" />
        var htmlChars = ['&~&amp;', '<~&lt;', '>~&gt;'];
        var r;
        var s = this;
        for (var i = 0; i < htmlChars.length; i++) {
            r = htmlChars[i].split('~');
            s = s.replace(new RegExp(r[0], 'g'), r[1]);
        }

        return s;
    },

    unescapseHTML: function() {
        ///<summary>
        /// 反转义字符中的HTML代码
        ///</summary>
        ///<returns type="STRING" />
        var htmlChars = ['&~&amp;', '<~&lt;', '>~&gt;'];
        var r;
        var s = this;
        for (var i = htmlChars.length - 1; i >= 0; i--) {
            r = htmlChars[i].split('~');
            s = s.replace(new RegExp(r[1], 'g'), r[0]);
        }
        return s;
    },

    format: function() {
        ///<summary>
        /// 格式化一个字符串，替换其中用大括号包含的数字及大括号，类似C#的format
        /// 如用第一个参数替换{0}
        ///</summary>
        ///<param name="values..." type="String">相关参数</param>
        ///<returns type="STRING" />
        var s = this;
        for (var i = 0; i < arguments.length; i++) {
            s = s.replace(new RegExp("\\{" + i + "\\}", "g"), arguments[i]);
        }
        return s;
    },

    formatBy: function(obj, funs) {
        ///<summary>
        /// 用对象格式化一个字符串
        /// 可以对格式化的字符中进行指定的函数替换或者截取
        ///</summary>
        ///<param name="obj" type="object">用来替换格式的对象</param>
        ///<param name="funs" type="object">相应的替换函数</param>
        ///<returns type="STRING" />
        funs = funs || {};
        return this.replace(/\$\{([^\}]+)\}/g, function(a, b) {
            var c = b.split(':');
            var d = c[0].split('|');
            if (d.length == 1) {
                if (d[0] in obj) return c[1] ? obj[d[0]].truncate(c[1].toInt()) : obj[d[0]];
            } else {
                var f = d[1].trim();
                if ((f in funs) && (d[0] in obj)) {
                    var r = funs[f](obj[d[0]]);
                    return c[1] ? r.truncate(c[1].toInt()) : r;
                }
            }
            return a;
        })
    },

    toHash: function(decode) {
        ///<summary>
        /// 把查询字符串（必须是查询字符串）转化为Hash对象
        /// 返回包含参数的hash对象
        ///</summary>
        ///<param name="decode" type="Boolean">是否要对字符串进行decode</param>
        ///<returns type="Hash" />
        decode = decode ? true : false;
        var ret = new Hash();
        var pairs = this.split('&');
        var pair = '';
        var tmp = [];
        for (var i = 0, ilen = pairs.length; i < ilen; i++) {
            pair = pairs[i];
            tmp = pair.split('=');
            if (tmp.length != 2) continue;
            if (decode) {
                ret.include(decodeURIComponent(tmp[0]), decodeURIComponent(tmp[1]));
            }
            else {
                ret.include(tmp[0], tmp[1]);
            }
        }
        return ret;
    }
});

/*
* MooTools的Element类的扩展
* 
*/
Element.implement({
    html: function(s) {
        ///<summary>
        /// 获取元素的HTML内容或者设置元素的HTML内容
        ///</summary>
        ///<param name="s" type="String">参数为空时，获取HTML内容；参数为字符串时，设置HTML的内容</param>
        ///<returns type="String" />
        if (s === undefined) {
            return this.get('html');
        }
        else {
            this.set('html', s + '');
            return s;
        }
    },
    
    toHash: function() {
        ///<summary>
        /// 把一个表单转成Hash对象
        ///</summary>
        ///<returns type="Hash" />
        return this.toQueryString().toHash();
    }
});

/*
* MooTools的Array类的扩展
* 
*/
Array.implement({
    random: function(num) {
        ///<summary>
        /// 从数组中随机选择指定个数的元素
        ///</summary>
        ///<param name="num" type="Number">要选取的元素个数</param>
        ///<returns type="ARRAY" />
        function _sort(a, b) {
            var ra = Math.random();
            var ret = 0;
            if (ra < 0.33) { ret = 0; }
            else if (ra < 0.66) { ret = -1; }
            else { ret = 1; }
            return ret;
        }

        var len = this.length;
        if (num < 0 || num > len) {
            return this;
        }

        this.sort(_sort).sort(_sort);
        return this.slice(0, num);
    },

    sortBy: function(options) {
        ///<summary>
        /// 把当前数据按照元素的某个属性排序
        ///</summary>
        ///<param name="prop" type="String">作为排序规则的属性名</param>
        ///<param name="type" type="String">排序方式，可以为asc（顺序）或者desc（逆序），默认为asc</param>
        ///<returns type="ARRAY" />
        options = options || {};
        prop = options.property || null;
        var ty = $type(prop);
        type = (options.type || 'asc').toLowerCase();

        return this.sort(function(a, b) {
            if ('string' == ty || 'number' == ty) {
                if (a[prop] > b[prop]) {
                    return type == 'desc' ? -1 : 1;
                }
                else if (a[prop] < b[prop]) {
                    return type == 'desc' ? 1 : -1;
                }
                else {
                    return 0;
                }
            }
            else {
                if (a > b) {
                    return type == 'desc' ? -1 : 1;
                }
                else if (a < b) {
                    return type == 'desc' ? 1 : -1;
                }
                else {
                    return 0;
                }
            }
        });
    }
});

/*
 * ImageWall.js
 * 图片墙滚动
 *
 * usage:
 * var my_iw = new ImageWall({
 *     buttons: [$('left'), $('right')],
 *     container: $('container'),
 *     itemTag: 'img'
 * }, 
 * {
 *     pertime: 4,
 *     direction: 'horizontal',
 *     styles: [['l_active', 'l_disable', 'l_hover'], ['r_active', 'r_disable', 'r_hover']]
 * });
 */

var ImageWall = new Class({
    Implements: Options,
    options: {
        direction: 'horizontal',
        pertime: 4,
        styles: []
    },

    _con: null,
    _btns: [],
    _itag: null,
    _styles: [],

    _total: 0,
    _diff: 0,
    _current: 0,

    _canb: false,
    _canf: false,

    _lsc: 0,
    _rsc: 0,

    initialize: function(settings, options) {
        var so = settings || {};
        this._con = so.container || null;
        this._btns = so.buttons || [];
        this._itag = so.itemTag || null;

        this.setOptions(options);
        if (this.options.styles.length == 2) {
            this._lsc = this.options.styles[0].length;
            this._rsc = this.options.styles[1].length;
        }

        if (this._btns.length < 2 || !this._con || !this._itag) {
            return;
        }

        // 计算各个项之间的距离
        this._collectInfo();

        // 检查按钮状态
        this._checkStatus();

        // 绑定事件
        this._bindEvents();
    },

    // 绑定相关事件
    _bindEvents: function() {
        var self = this;
        this._btns.each(function(el, i) {
            var sh = null, so = null, c = false;
            if (this.lsc == 3 && this.rsc == 3) {
                sh = this.options.styles[i][2];
                so = this.options.styles[i][0];
                c = i ? this._canf : this._canb;
            }
            el.addEvents({
                'mouseenter': function() {
                    if (sh && c) {
                        this.set('class', sh);
                    }
                },
                'mouseout': function() {
                    if (so && c) {
                        this.set('class', so);
                    }
                },
                'click': function() {
                    this.blur();
                    self._scrollItem(i);
                    return false;
                }
            });
        });
    },

    // 滚动元素
    _scrollItem: function(i) {
        var next = this._current;
        if (i) {
            var temp = this._current + this.options.pertime;
            if (temp < this._total) {
                next = temp;
            }
        }
        else {
            var temp = this._current - this.options.pertime;
            if (temp >= 0) {
                next = temp;
            }
        }

        if (next == this._current) {
            return;
        }

        this._current = next;

        if ('horizontal' == this.options.direction) {
            this._con.tween('left', -next * this._diff);
        }
        else {
            this._con.tween('top', -next * this._diff);
        }

        this._checkStatus();
    },

    //计算各个项之间的距离
    _collectInfo: function() {
        var tp = this._con.getElements(this._itag);
        this._total = tp.length;

        if (this._total < 2) {
            this._diff = 0;
            return;
        }

        if ('horizontal' == this.options.direction) {
            this._diff = tp[1].getPosition().x - tp[0].getPosition().x;
        }
        else {
            this._diff = tp[1].getPosition().y - tp[0].getPosition().y;
        }
    },

    // 检查按钮状态
    _checkStatus: function() {
        if (this._lsc < 2 || this._rsc < 2) {
            return;
        }

        // 可以向回滚动
        if (this._current - this.options.pertime >= 0) {
            this._btns[0].set('class', this.options.styles[0][0]);
            this._canb = true;
        }
        else {
            this._btns[0].set('class', this.options.styles[0][1]);
            this._canb = false;
        }

        // 可以向前滚动
        if (this._current + this.options.pertime < this._total) {
            this._btns[1].set('class', this.options.styles[1][0]);
            this._canf = true;
        }
        else {
            this._btns[1].set('class', this.options.styles[1][1]);
            this._canf = false;
        }
    }
});